﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CodeGenerationPipeline.Contracts;
using CodeGenerationPipeline;
using System.IO;
using System.Diagnostics;
using WSDLGenerator;
using AbstraX.Bindings;
using Metaspec;
using VisualStudioProvider;
using AbstraX.ServerInterfaces;
using System.Reflection;
using AbstraX.Contracts;

namespace DomainServices
{
    public class DomainServicesGenerator : BaseGenerator
    {
        public override event WatchProcess OnWatchProcess;

        public override string Name
        {
            get
            {
                return "Domain Services Generator";
            }
        }

        public override string Description
        {
            get 
            {
                return "";
            }
        }

        public override ICodeGenerationPackage GenerateFrom(Dictionary<string, IElementBuild> builds, DirectoryInfo workspaceDirectory)
        {
            var structure = pipelineStep.ProjectStructure;
            var projectRoot = structure.ProjectRoot;
            var webProject = (VSProject) projectRoot.FindLayer("Presentation");
            var projectItem = (VSProjectItem) structure;
            var csFile = projectItem.ICsFile;
            var csProject = csFile.getProject();

            csProject.parse(true, false);

            var unit = (CsCompilationUnit)csFile.getCompilationUnit();
            var serviceNamespace = (CsNamespace)unit.declarations[0];
            var serviceClass = (CsClass)serviceNamespace.member_declarations[0];
            string serviceResourceName = string.Empty;
            var className = serviceClass.identifier.identifier;
            var namespaceIdentifier = serviceNamespace.qualified_identifier;

            namespaceIdentifier.ToList<CsQualifiedIdentifierPart>().ForEach(p => serviceResourceName += p.identifier.identifier + "-");
            serviceResourceName += className;

            var iter = webProject.Select(string.Format("{0}:Project/{0}:ProjectExtensions/{0}:VisualStudio/{0}:FlavorProperties/{0}:WebProjectProperties/{0}:DevelopmentServerPort", webProject.XPathNamespacePrefix));

            iter.MoveNext();

            var serverPort = iter.Current.Value;

            var startInfo = new ProcessStartInfo
            {
                FileName = Path.Combine(sDKFolder, "SvcUtil.exe"),
                Arguments = "/directory:" + workspaceDirectory + string.Format("  http://localhost:{0}/Services/{1}.svc?wsdl", serverPort, serviceResourceName),
                CreateNoWindow = true
            };

            var process = new Process
            {
                StartInfo = startInfo,
            };

            this.workspaceDirectory = workspaceDirectory.FullName;

            OnWatchProcess(this, process, true, 60000);

            if (this.Files.Values.Where(f => f.Extension == ".cs").Count() != 1)
            {
                Debugger.Break();
            }
            else
            {
                var file = this.Files.Values.Where(f => f.Extension == ".cs").Single();
                var path = file.FullName;
                var buffer = File.ReadAllText(path).ToCharArray();
                var csProxyFile = ICsFileFactory.create(buffer, path);
                var project = ICsProjectFactory.create(project_namespace.pn_project_namespace);

                project.addFiles(csProxyFile);

                //parsing
                project.parse(true, false);

                className += "SoapClient";

                unit = (CsCompilationUnit)csProxyFile.getCompilationUnit();
                var proxyClass = (CsClass)unit.declarations.Where(n => n is CsClass && ((CsClass)n).identifier.identifier == className).Single();

                PackageGenerator.GeneratePackage(builds)
                    .ApplyPortType(proxyClass)
                    .Support()
                        .When(() => DefaultDataContextOperation.GetAll)
                            .MapOperation((CsClass c, IElement e, DefaultDataContextOperation o) => c.member_declarations.Where(m => m is CsMethod && ((CsMethod)m).identifier.identifier == "Get" + e.Name + "s").Single())
                        .When(() => OptionalDataContextOperation.Insert | OptionalDataContextOperation.Update | OptionalDataContextOperation.Delete)
                            .MapOperation((CsClass c, IElement e, OptionalDataContextOperation o) => c.member_declarations.Where(m => m is CsMethod && ((CsMethod)m).identifier.identifier == "SubmitChanges").Single());
                        
                    //.Requirements()
                    //    .AddIncludeFile("", "", BuildAction.BuildActionCompile, "", "")
                    //.BuildPackage();

                return null;
            }

            throw new Exception("");
        }

        public override ICodeGenerationPackage GenerateFromPackage(ICodeGenerationPackage incomingPackage)
        {
            this.workspaceDirectory = incomingPackage.WorkspaceDirectory.FullName;

            return null;
        }

        public override void OnError(int errorCode, Exception exception, string error)
        {
            Debugger.Break();

            base.OnError(errorCode, exception, error);
        }

        public override void OnProcessExited(int exitCode)
        {
            if (exitCode != 0)
            {
                Debugger.Break();
            }
            else
            {
                Debug.WriteLine("\r\nFiles:\r\n");

                foreach (var file in this.Files.Values)
                {
                    Debug.WriteLine(file.Name);
                }
            }

            base.OnProcessExited(exitCode);
        }

        public override void OnProcessTimeout()
        {
            Debugger.Break();
            base.OnProcessTimeout();
        }

        public override void OnFileCreated(FileInfo file)
        {
            Debug.WriteLine("File created: " + file.Name);
            base.OnFileCreated(file);
        }

        public override void OnFileChanged(FileInfo file)
        {
            Debug.WriteLine("File changed: " + file.Name);
            base.OnFileChanged(file);
        }

        public override void OnFileRenamed(FileInfo file, FileInfo oldFile)
        {
            Debug.WriteLine("File renamed: " + file.Name);
            base.OnFileRenamed(file, oldFile);
        }

        public override void OnFileDeleted(FileInfo file)
        {
            Debug.WriteLine("File deleted: " + file.Name);
            base.OnFileDeleted(file);
        }
    }
}
